/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view.symbols;

import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.ValueNode;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.connect5.numerical.DoubleSumRelation;
import org.jfonia.connect5.numerical.UnidirectionalDoubleSumRelation;
import org.jfonia.constants.ViewConstants;

/**
 *
 * @author Rik Bauwens
 */
public abstract class StaffSymbol extends Symbol implements IStaffSymbol
{
        private ValueNode<Double> frameX;
        private ValueNode<Double> staffY;

        private MutableValueNode<Double> absoluteXNode;
        private MutableValueNode<Double> absoluteYNode;

        private MutableValueNode<Double> xNode;
        private MutableValueNode<Double> yNode;
        private MutableValueNode<Double> widthNode;
        private MutableValueNode<Double> heightNode;

        private MutableValueNode<Double> xOffsetNode;
        private MutableValueNode<Double> yOffsetNode;

        protected MutableValueNode<Double> preXNode;
        protected MutableValueNode<Double> postXNode;
        protected MutableValueNode<Double> preYNode;
        protected MutableValueNode<Double> postYNode;

        protected MutableValueNode<Double> floorYNode;
        protected MutableValueNode<Double> ceilingYNode;

        private boolean selected;

        public StaffSymbol(ValueNode<Double> frameX, ValueNode<Double> staffY,
                      ValueNode<Double> xNode, ValueNode<Double> yNode)
        {
                this.frameX = frameX;
                this.staffY = staffY;

                this.xNode = new BasicValueNode<Double>(0.0);
                xOffsetNode = new BasicValueNode<Double>(0.0);
                new DoubleSumRelation(xNode, xOffsetNode, this.xNode);
                absoluteXNode = new BasicValueNode<Double>(0.0);
                new DoubleSumRelation(frameX, this.xNode, absoluteXNode);

                this.yNode = new BasicValueNode<Double>(0.0);
                yOffsetNode = new BasicValueNode<Double>(0.0);
                new DoubleSumRelation(yNode, yOffsetNode, this.yNode);
                absoluteYNode = new BasicValueNode<Double>(0.0);
                new DoubleSumRelation(staffY, this.yNode, absoluteYNode);

                this.widthNode = new BasicValueNode<Double>(0.0);
                this.heightNode = new BasicValueNode<Double>(0.0);

                this.preXNode = new BasicValueNode<Double>(0.0);
                this.postXNode = new BasicValueNode<Double>(0.0);
                this.preYNode = new BasicValueNode<Double>(0.0);
                this.postYNode = new BasicValueNode<Double>(0.0);
                
                this.floorYNode = new BasicValueNode<Double>(0.0);
                new UnidirectionalDoubleSumRelation(getAbsoluteYNode(), postYNode, floorYNode);
                this.ceilingYNode = new BasicValueNode<Double>(0.0);
                new UnidirectionalDoubleSumRelation(getAbsoluteYNode(), preYNode, ceilingYNode);
                selected = false;
                init();
        }

        private void init()
        {
		xNode.addObserver( new Observer() {
                        public void onNotify(Object source)
                        {

                        }
		});
		yNode.addObserver( new Observer() {
                        public void onNotify(Object source)
                        {

                        }
		});
		widthNode.addObserver( new Observer() {
                        public void onNotify(Object source)
                        {

                        }
		});
		heightNode.addObserver( new Observer() {
                        public void onNotify(Object source)
                        {

                        }
		});
        }

        protected ValueNode<Double> getFrameX()
        {
                return frameX;
        }

        protected ValueNode<Double> getStaffY()
        {
                return staffY;
        }

        protected MutableValueNode<Double> getXNode()
        {
                return xNode;
        }

        protected MutableValueNode<Double> getYNode()
        {
                return yNode;
        }

        public ValueNode<Double> getAbsoluteXNode()
        {
                return absoluteXNode;
        }

        public ValueNode<Double> getAbsoluteYNode()
        {
                return absoluteYNode;
        }

        public MutableValueNode<Double> getWidthNode()
        {
                return widthNode;
        }

        public MutableValueNode<Double> getHeightNode()
        {
                return heightNode;
        }

        public ValueNode<Double> getFloorYNode()
        {
                return floorYNode;
        }

        public ValueNode<Double> getCeilingYNode()
        {
                return ceilingYNode;
        }

        public double getX()
        {
                return xNode.getValue();
        }

        public double getY()
        {
                return yNode.getValue();
        }

        public double getAbsoluteX()
        {
                return absoluteXNode.getValue();
        }

        public double getAbsoluteY()
        {
                return absoluteYNode.getValue();
        }

        public double getPreX()
        {
                return ViewConstants.SELECTIONBOX_SPACING + preXNode.getValue();
        }

        public double getPostX()
        {
                return ViewConstants.SELECTIONBOX_SPACING + postXNode.getValue();
        }

        public double getPreY()
        {
                return ViewConstants.SELECTIONBOX_SPACING + preYNode.getValue();
        }

        public double getPostY()
        {
                return ViewConstants.SELECTIONBOX_SPACING + postYNode.getValue();
        }

        public void setSelected(boolean selected)
        {
                this.selected = selected;
        }

        public boolean intersectsTo(Rectangle2D rectangle)
        {
                return getBounds().intersects(rectangle);
        }

        public boolean intersectsAbsoluteTo(Rectangle2D rectangle)
        {
                return getAbsoluteBounds().intersects(rectangle);
        }

        public Rectangle2D getBounds()
        {
                return new Rectangle2D.Double(getX() - getPreX(), getY() - getPreY(),
                                              getPostX() + getPreX(), getPostY() + getPreY());
        }

        public Rectangle2D getAbsoluteBounds()
        {
                return new Rectangle2D.Double(getAbsoluteX() - getPreX(), getAbsoluteY() - getPreY(),
                                              getPostX() + getPreX(), getPostY() + getPreY());
        }

        public void paintSymbol(Graphics2D g)
        {
                if(selected)
                {
                        g.setColor(ViewConstants.SELECTIONBOX_EDGE_COLOR);
                        g.drawRoundRect((int) (getX() - getPreX() /*- ViewConstants.SELECTIONBOX_SPACING*/),
                                        (int) (getY() - getPreY() /*- ViewConstants.SELECTIONBOX_SPACING*/),
                                        (int) (getBounds().getWidth() /*+ 2 * ViewConstants.SELECTIONBOX_SPACING*/),
                                        (int) (getBounds().getHeight() /*+ 2 * ViewConstants.SELECTIONBOX_SPACING*/),
                                        ViewConstants.ROUNDRECT_ARC_WIDTH, ViewConstants.ROUNDRECT_ARC_HEIGHT);
                }
                g.setColor(ViewConstants.SYMBOL_COLOR);
        }

}
